/*	$Id: if_ether.c 6 2008-07-29 02:30:10Z phrakt $	*/
/*
 * Copyright (c) 2003 Jean-Francois Brousseau <jfb@openbsd.org>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
 * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL  DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
/*
 * Ethernet interface emulation
 * ============================
 *
 * The following code supports emulation of both original Ethernet and
 * IEEE 802.3 frame formats (as specified in RFC 894 and RFC 1042,
 * respectively).
 *
 *
 * For Ethernet Types assigned numbers, consult the list as part of
 * RFC 1700 - ASSIGNED NUMBERS
 */

#include <sys/param.h>
#include <sys/stat.h>
#include <sys/ioctl.h>

#if defined(__OpenBSD__) || defined(__NetBSD__)
#include <net/if_dl.h>
#include <net/if_types.h>

#include <ifaddrs.h>

#elif defined(__linux__)
#include <net/if_arp.h>

/* stupid linux defines endianness-swapping functions in netinet code */
#include <netinet/in.h>
#endif

#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>

#include "if.h"
#include "pkt.h"
#include "log.h"
#include "dlink.h"
#include "proto.h"
#include "pforge.h"
#include "private.h"
#include "proto_ids.h"


#define PFIF_ETHER_ADDRLEN       6     /* address length in bytes */
#define PFIF_ETHER_TYPELEN       2     /* EtherType length */
#define PFIF_ETHER_CRCLEN        4     /* Cyclic Redundancy Check length */
#define PFIF_ETHER_MINFRMLEN    64     /* minimum frame length */
#define PFIF_ETHER_MAXFRMLEN  1518     /* max frame length */

#define PFIF_ETHER_HDRLEN ((PFIF_ETHER_ADDRLEN * 2) + PFIF_ETHER_TYPELEN)
#define PFIF_8023_HDRLEN  (PFIF_ETHER_HDRLEN + sizeof(struct pf_ether_8023llc))

#define PFIF_ETHER_MAXMTU \
	(PFIF_ETHER_MAXFRMLEN - PFIF_ETHER_HDRLEN - PFIF_ETHER_CRCLEN)
#define PFIF_ETHER_MINMTU \
	(PFIF_ETHER_MINFRMLEN - PFIF_ETHER_HDRLEN - PFIF_ETHER_CRCLEN)

#define PFIF_ETHER_ADDRFMT   "%02x:%02x:%02x:%02x:%02x:%02x"


/* ethernet types */
#define PFIF_ETHERTYPE_PUP    0x0200
#define PFIF_ETHERTYPE_IP     0x0800    /* Internet protocol */
#define PFIF_ETHERTYPE_ARP    0x0806    /* address resolution protocol */
#define PFIF_ETHERTYPE_RARP   0x8035    /* reverse ARP */
#define PFIF_ETHERTYPE_IP6    0x86dd    /* IP version 6 */






struct pf_ether_hdr {
	uint8_t   eh_dst[PFIF_ETHER_ADDRLEN];	/* destination address */
	uint8_t   eh_src[PFIF_ETHER_ADDRLEN];	/* source address */
	uint16_t  eh_type;			/* type (len for 802.3) */
};

struct pf_ether_8023llc {
	uint8_t   el_dsap;
	uint8_t   el_ssap;
	uint32_t  el_cntl:  8;
	uint32_t  el_org:  24;
	uint16_t  el_type;

};


/* Ethernet-specific interface data */
struct pf_netif_ether {
};


int   pf_ether_init    (void);
void  pf_ether_fini    (void);
int   pf_ether_input   (PF_NETIF *, PF_PKT *);
int   pf_ether_output  (PF_NETIF *, PF_PKT *);
void  pf_ether_print   (PF_NETIF *, PF_PKT *, struct pf_ether_hdr *);


struct pf_netif_ops pf_ether_ops = {
	pf_ether_init,
	pf_ether_fini,
	NULL,
	NULL,
	pf_ether_input,
	pf_ether_output,
	NULL,
	pf_ether_print
};



/*
 * pf_ether_init()
 *
 * Initialization routine for the Ethernet.
 * Returns 0 on success, or -1 on failure.
 */

int
pf_ether_init(void)
{
	return (0);
}


/*
 * pf_ether_fini()
 *
 */

void
pf_ether_fini(void)
{

}


/*
 * pf_ether_input()
 *
 * Input routine to read Ethernet frames and decapsulate the Ethernet layer.
 */

int
pf_ether_input(PF_NETIF *ifp, PF_PKT *pkt)
{
	int prid, ret;
	struct pf_ether_hdr *hdr;
	PF_PBUF *pbuf;

	pbuf = PFPCHAIN_HEAD(&(pkt->pkt_bufs));

	/*
	 * At this point, the header should always be found contiguous at
	 * the start of the first buffer.  Set the packet's offset past the
	 * header for the next protocol and tag the start of the packet.
	 */
	hdr = (struct pf_ether_hdr *)PFPBUF_START(pbuf);
	pkt->pkt_off += PFIF_ETHER_HDRLEN;

	pf_pkt_tag(pkt, 0, PFPR_HW_ETHER, NULL);

	prid = PFPR_INVAL;

	switch (ntohs(hdr->eh_type)) {
	case PFIF_ETHERTYPE_PUP:
		prid = PFPR_INET_PUP;
		break;
	case PFIF_ETHERTYPE_IP:
		prid = PFPR_INET_IP;
		break;
	case PFIF_ETHERTYPE_ARP:
		prid = PFPR_NONE_ARP;
		break;
	case PFIF_ETHERTYPE_RARP:
		prid = PFPR_NONE_RARP;
		break;
	case PFIF_ETHERTYPE_IP6:
		prid = PFPR_INET_IPV6;
		break;
	default:
		break;
	}

	pf_ether_print(ifp, pkt, hdr);
	pf_proto_input(prid, pkt);
}


/*
 * pf_ether_output()
 *
 */

int
pf_ether_output(PF_NETIF *ifp, PF_PKT *pkt)
{
	uint8_t bigbuf[2048];
	struct pf_ether_hdr *hdr;

#if 0
	if (flen < PFIF_ETHER_MINFRMLEN) {
		/* pad with 0's */
	}
#endif

	hdr = (struct pf_ether_hdr *)bigbuf;
}


/*
 * pf_ether_print()
 *
 * Print a human-readable version of the data contained in an Ethernet header.
 */

void
pf_ether_print(PF_NETIF *ifp, PF_PKT *pkt, struct pf_ether_hdr *hdr)
{

	pf_log(pforge_chan, PFLOG_INFO, "Dst: " PFIF_ETHER_ADDRFMT,
	    hdr->eh_dst[0], hdr->eh_dst[1], hdr->eh_dst[2],
	    hdr->eh_dst[3], hdr->eh_dst[4], hdr->eh_dst[5]);

	pf_log(pforge_chan, PFLOG_INFO, "   Src: " PFIF_ETHER_ADDRFMT,
	    hdr->eh_src[0], hdr->eh_src[1], hdr->eh_src[2],
	    hdr->eh_src[3], hdr->eh_src[4], hdr->eh_src[5]);

	pf_log(pforge_chan, PFLOG_INFO, "   Type: 0x%x\n", ntohs(hdr->eh_type));
}
